package com.yjyw.tiexie.widget.tab;


import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.app.ActionBar;
import android.content.Context;
import android.content.res.ColorStateList;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.database.DataSetObserver;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.ColorFilter;
import android.graphics.Paint;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Typeface;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.Handler;
import android.os.Looper;
import android.os.SystemClock;
import android.text.Layout;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewOutlineProvider;
import android.view.ViewParent;
import android.view.WindowManager;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityNodeInfo;
import android.view.animation.AccelerateDecelerateInterpolator;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.Interpolator;
import android.view.animation.LinearInterpolator;
import android.widget.HorizontalScrollView;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;

import androidx.annotation.ColorInt;
import androidx.annotation.DrawableRes;
import androidx.annotation.LayoutRes;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.StringRes;
import androidx.appcompat.widget.TintTypedArray;
import androidx.core.util.Pools;
import androidx.core.view.GravityCompat;
import androidx.core.view.ViewCompat;
import androidx.core.widget.TextViewCompat;
import androidx.interpolator.view.animation.FastOutLinearInInterpolator;
import androidx.interpolator.view.animation.FastOutSlowInInterpolator;
import androidx.interpolator.view.animation.LinearOutSlowInInterpolator;
import androidx.viewpager.widget.PagerAdapter;
import androidx.viewpager.widget.ViewPager;

import com.yjyw.tiexie.R;
import com.google.android.material.tabs.TabLayout;

import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import static android.R.attr.maxWidth;
import static androidx.appcompat.widget.AppCompatDrawableManager.get;
import static androidx.viewpager.widget.ViewPager.SCROLL_STATE_DRAGGING;
import static androidx.viewpager.widget.ViewPager.SCROLL_STATE_IDLE;
import static androidx.viewpager.widget.ViewPager.SCROLL_STATE_SETTLING;

public class XTabLayout extends HorizontalScrollView {
    private static final int DEFAULT_HEIGHT_WITH_TEXT_ICON = 72;
    private static final int DEFAULT_GAP_TEXT_ICON = 8;
    private static final int INVALID_WIDTH = -1;
    private static final int DEFAULT_HEIGHT = 48;
    private static final int TAB_MIN_WIDTH_MARGIN = 56;
    private static final int FIXED_WRAP_GUTTER_MIN = 16;
    private static final int SELECTED_TAB_ADD_WIDTH = 20;
    private static final int MOTION_NON_ADJACENT_OFFSET = 24;
    private static final int ANIMATION_DURATION = 300;
    private static final Pools.Pool<Tab> sTabPool = new Pools.SynchronizedPool<>(16);
    private static final int MODE_SCROLLABLE = 0;
    private static final int MODE_FIXED = 1;
    private static final int GRAVITY_FILL = 0;
    private static final int GRAVITY_CENTER = 1;
    private static final int[] APPCOMPAT_CHECK_ATTRS = {R.attr.colorPrimary};
    private final DisplayMetrics dm;
    private final ArrayList<Tab> mTabs = new ArrayList<>();
    private final SlidingTabStrip mTabStrip;
    private final int mTabTextAppearance;
    private final boolean xTabTextBold;
    private final boolean xTabTextSelectedBold;
    private final int xTabBackgroundColor;
    private final int xTabSelectedBackgroundColor;
    private final int mRequestedTabMinWidth;
    private final int mRequestedTabMaxWidth;
    private final int mScrollableTabMinWidth;
    private final List<OnTabSelectedListener> mOnTabSelectedListenerList = new ArrayList<>();
    private final Pools.Pool<TabView> mTabViewPool = new Pools.SimplePool<>(12);
    private boolean xTabTextAllCaps = false;
    private boolean xTabDividerWidthWidthText = false;
    private Tab mSelectedTab;
    private int mTabPaddingStart;
    private int mTabPaddingTop;
    private int mTabPaddingEnd;
    private int mTabPaddingBottom;
    private ColorStateList mTabTextColors;
    private int mTabTextSize = 0;
    private int mTabSelectedTextSize = 0;
    private float mTabTextMultiLineSize;
    private int mTabMaxWidth = Integer.MAX_VALUE;
    private int xTabDisplayNum;
    private int mContentInsetStart;
    private int mTabGravity;
    private int mMode;
    private int dividerWidth;
    private int dividerHeight;
    private int dividerColor;
    private int dividerGravity;
    private OnTabSelectedListener mOnTabSelectedListener;
    private ValueAnimatorCompat mScrollAnimator;
    private ViewPager mViewPager;
    private PagerAdapter mPagerAdapter;
    private DataSetObserver mPagerAdapterObserver;
    private TabLayoutOnPageChangeListener mPageChangeListener;

    public XTabLayout(Context context) {
        this(context, null);
    }

    public XTabLayout(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public XTabLayout(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        checkAppCompatTheme(context);
        setHorizontalScrollBarEnabled(false);
        mTabStrip = new SlidingTabStrip(context);
        super.addView(mTabStrip, 0, new LayoutParams(
                LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT));
        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.XTabLayout,
                defStyleAttr, R.style.Widget_Design_TabLayout);
        mTabStrip.setSelectedIndicatorHeight(
                a.getDimensionPixelSize(R.styleable.XTabLayout_xTabIndicatorHeight, dpToPx(2)));
        mTabStrip.setmSelectedIndicatorWidth(
                a.getDimensionPixelSize(R.styleable.XTabLayout_xTabIndicatorWidth, 0));
        mTabStrip.setSelectedIndicatorColor(a.getColor(R.styleable.XTabLayout_xTabIndicatorColor, 0));
        mTabPaddingStart = mTabPaddingTop = mTabPaddingEnd = mTabPaddingBottom = a
                .getDimensionPixelSize(R.styleable.XTabLayout_xTabPadding, 0);
        mTabPaddingStart = a.getDimensionPixelSize(R.styleable.XTabLayout_xTabPaddingStart,
                mTabPaddingStart);
        mTabPaddingTop = a.getDimensionPixelSize(R.styleable.XTabLayout_xTabPaddingTop,
                mTabPaddingTop);
        mTabPaddingEnd = a.getDimensionPixelSize(R.styleable.XTabLayout_xTabPaddingEnd,
                mTabPaddingEnd);
        mTabPaddingBottom = a.getDimensionPixelSize(R.styleable.XTabLayout_xTabPaddingBottom,
                mTabPaddingBottom);
        xTabTextAllCaps = a.getBoolean(R.styleable.XTabLayout_xTabTextAllCaps, false);
        mTabTextAppearance = a.getResourceId(R.styleable.XTabLayout_xTabTextAppearance,
                R.style.TextAppearance_Design_Tab);
        mTabTextSize = a.getInt(R.styleable.XTabLayout_xTabTextSize, 14);
        xTabTextBold = a.getBoolean(R.styleable.XTabLayout_xTabTextBold, false);
        mTabSelectedTextSize = a.getInt(R.styleable.XTabLayout_xTabSelectedTextSize, 14);
        xTabTextSelectedBold = a.getBoolean(R.styleable.XTabLayout_xTabTextSelectedBold, false);
        final TypedArray ta = context.obtainStyledAttributes(mTabTextAppearance,
                R.styleable.TextAppearance);
        try {
            if (mTabTextSize == 0) {
                mTabTextSize = ta.getDimensionPixelSize(R.styleable.TextAppearance_android_textSize, 0);
            }
            mTabTextColors = ta.getColorStateList(R.styleable.TextAppearance_android_textColor);
        } finally {
            ta.recycle();
        }
        if (a.hasValue(R.styleable.XTabLayout_xTabTextColor)) {
            mTabTextColors = a.getColorStateList(R.styleable.XTabLayout_xTabTextColor);
        }
        if (a.hasValue(R.styleable.XTabLayout_xTabSelectedTextColor)) {
            final int selected = a.getColor(R.styleable.XTabLayout_xTabSelectedTextColor, 0);
            mTabTextColors = createColorStateList(mTabTextColors.getDefaultColor(), selected);
        }
        xTabDisplayNum = a.getInt(R.styleable.XTabLayout_xTabDisplayNum, 0);
        mRequestedTabMinWidth = a.getDimensionPixelSize(R.styleable.XTabLayout_xTabMinWidth,
                INVALID_WIDTH);
        mRequestedTabMaxWidth = a.getDimensionPixelSize(R.styleable.XTabLayout_xTabMaxWidth,
                INVALID_WIDTH);
        xTabBackgroundColor = a.getColor(R.styleable.XTabLayout_xTabBackgroundColor, 0);
        xTabSelectedBackgroundColor = a.getColor(R.styleable.XTabLayout_xTabSelectedBackgroundColor, 0);
        mContentInsetStart = a.getDimensionPixelSize(R.styleable.XTabLayout_xTabContentStart, 0);
        mMode = a.getInt(R.styleable.XTabLayout_xTabMode, MODE_FIXED);
        mTabGravity = a.getInt(R.styleable.XTabLayout_xTabGravity, GRAVITY_FILL);
        dividerWidth = a.getDimensionPixelSize(R.styleable.XTabLayout_xTabDividerWidth, 0);
        dividerHeight = a.getDimensionPixelSize(R.styleable.XTabLayout_xTabDividerHeight, 0);
        dividerColor = a.getColor(R.styleable.XTabLayout_xTabDividerColor, Color.BLACK);
        dividerGravity = a.getInteger(R.styleable.XTabLayout_xTabDividerGravity, DividerDrawable.CENTER);
        xTabDividerWidthWidthText = a.getBoolean(R.styleable.XTabLayout_xTabDividerWidthWidthText, false);
        a.recycle();
        dm = new DisplayMetrics();
        final Resources res = getResources();
        mTabTextMultiLineSize = res.getDimensionPixelSize(R.dimen.design_tab_text_size_2line);
        mScrollableTabMinWidth = res.getDimensionPixelSize(R.dimen.design_tab_scrollable_min_width);
        applyModeAndGravity();
        addDivider();
    }

    private static ColorStateList createColorStateList(int defaultColor, int selectedColor) {
        final int[][] states = new int[2][];
        final int[] colors = new int[2];
        int i = 0;
        states[i] = SELECTED_STATE_SET;
        colors[i] = selectedColor;
        i++;
        states[i] = EMPTY_STATE_SET;
        colors[i] = defaultColor;
        i++;
        return new ColorStateList(states, colors);
    }

    private static void checkAppCompatTheme(Context context) {
        TypedArray a = context.obtainStyledAttributes(APPCOMPAT_CHECK_ATTRS);
        final boolean failed = !a.hasValue(0);
        if (a != null) {
            a.recycle();
        }
        if (failed) {
            throw new IllegalArgumentException("You need to use a Theme.AppCompat theme "
                    + "(or descendant) with the design library.");
        }
    }

    private void addDivider() {
        post(new Runnable() {
            @Override
            public void run() {
                if (dividerWidth > 0) {
                    LinearLayout linearLayout = (LinearLayout) getChildAt(0);
                    linearLayout.setShowDividers(LinearLayout.SHOW_DIVIDER_MIDDLE);
                    DividerDrawable dividerDrawable = new DividerDrawable(getContext());
                    dividerDrawable.setDividerSize(dividerWidth, dividerHeight);
                    dividerDrawable.setColor(dividerColor);
                    dividerDrawable.setGravity(dividerGravity);
                    linearLayout.setDividerDrawable(dividerDrawable);
                }
            }
        });
    }

    public void setDividerSize(int width, int height) {
        dividerWidth = width;
        dividerHeight = height;
        addDivider();
    }

    public void setDividerColor(int color) {
        dividerColor = color;
        addDivider();
    }

    public void setDividerGravity(int gravity) {
        dividerGravity = gravity;
        addDivider();
    }

    public void setAllCaps(boolean allCaps) {
        xTabTextAllCaps = allCaps;
    }

    public void setSelectedTabIndicatorColor(@ColorInt int color) {
        mTabStrip.setSelectedIndicatorColor(color);
    }

    public void setSelectedTabIndicatorHeight(int height) {
        mTabStrip.setSelectedIndicatorHeight(height);
    }

    public void setxTabDisplayNum(int xTabDisplayNum) {
        this.xTabDisplayNum = xTabDisplayNum;
    }

    private void setScrollPosition(int position, float positionOffset, boolean updateSelectedText) {
        setScrollPosition(position, positionOffset, updateSelectedText, true);
    }

    private void setScrollPosition(int position, float positionOffset, boolean updateSelectedText,
                                   boolean updateIndicatorPosition) {
        final int roundedPosition = Math.round(position + positionOffset);
        if (roundedPosition < 0 || roundedPosition >= mTabStrip.getChildCount()) {
            return;
        }
        if (updateIndicatorPosition) {
            mTabStrip.setIndicatorPositionFromTabPosition(position, positionOffset);
        }
        if (mScrollAnimator != null && mScrollAnimator.isRunning()) {
            mScrollAnimator.cancel();
        }
        scrollTo(calculateScrollXForTab(position, positionOffset), 0);
        if (updateSelectedText) {
            setSelectedTabView(roundedPosition);
        }
    }

    private float getScrollPosition() {
        return mTabStrip.getIndicatorPosition();
    }

    public void addTab(@NonNull Tab tab) {
        addTab(tab, mTabs.isEmpty());
    }

    public void addTab(@NonNull Tab tab, int position) {
        addTab(tab, position, mTabs.isEmpty());
    }

    private void addTab(@NonNull Tab tab, boolean setSelected) {
        if (tab.mParent != this) {
            throw new IllegalArgumentException("Tab belongs to a different TabLayout.");
        }
        addTabView(tab, setSelected);
        configureTab(tab, mTabs.size());
        if (setSelected) {
            tab.select();
        }
    }

    private void addTab(@NonNull Tab tab, int position, boolean setSelected) {
        if (tab.mParent != this) {
            throw new IllegalArgumentException("Tab belongs to a different TabLayout.");
        }
        addTabView(tab, position, setSelected);
        configureTab(tab, position);
        if (setSelected) {
            tab.select();
        }
    }

    private void addTabFromItemView(@NonNull TabItem item) {
        final Tab tab = newTab();
        if (item.mText != null) {
            tab.setText(item.mText);
        }
        if (item.mIcon != null) {
            tab.setIcon(item.mIcon);
        }
        if (item.mCustomLayout != 0) {
            tab.setCustomView(item.mCustomLayout);
        }
        addTab(tab);
    }

    public void setOnTabSelectedListener(OnTabSelectedListener onTabSelectedListener) {
        mOnTabSelectedListener = onTabSelectedListener;
    }

    public void addOnTabSelectedListener(OnTabSelectedListener onTabSelectedListener) {
        mOnTabSelectedListenerList.add(onTabSelectedListener);
    }

    @NonNull
    public Tab newTab() {
        Tab tab = sTabPool.acquire();
        if (tab == null) {
            tab = new Tab();
        }
        tab.mParent = this;
        tab.mView = createTabView(tab);
        return tab;
    }

    public int getTabCount() {
        return mTabs.size();
    }

    @Nullable
    public Tab getTabAt(int index) {
        return mTabs.get(index);
    }

    private int getSelectedTabPosition() {
        return mSelectedTab != null ? mSelectedTab.getPosition() : -1;
    }

    public void removeTab(Tab tab) {
        if (tab.mParent != this) {
            throw new IllegalArgumentException("Tab does not belong to this TabLayout.");
        }
        removeTabAt(tab.getPosition());
    }

    private void removeTabAt(int position) {
        final int selectedTabPosition = mSelectedTab != null ? mSelectedTab.getPosition() : 0;
        removeTabViewAt(position);
        final Tab removedTab = mTabs.remove(position);
        if (removedTab != null) {
            removedTab.reset();
            sTabPool.release(removedTab);
        }
        final int newTabCount = mTabs.size();
        for (int i = position; i < newTabCount; i++) {
            mTabs.get(i).setPosition(i);
        }
        if (selectedTabPosition == position) {
            selectTab(mTabs.isEmpty() ? null : mTabs.get(Math.max(0, position - 1)));
        }
    }

    public void removeAllTabs() {
        for (int i = mTabStrip.getChildCount() - 1; i >= 0; i--) {
            removeTabViewAt(i);
        }
        for (final Iterator<Tab> i = mTabs.iterator(); i.hasNext(); ) {
            final Tab tab = i.next();
            i.remove();
            tab.reset();
            sTabPool.release(tab);
        }
        mSelectedTab = null;
    }

    @TabLayout.Mode
    public int getTabMode() {
        return mMode;
    }

    public void setTabMode(@TabLayout.Mode int mode) {
        if (mode != mMode) {
            mMode = mode;
            applyModeAndGravity();
        }
    }

    @TabLayout.TabGravity
    public int getTabGravity() {
        return mTabGravity;
    }

    public void setTabGravity(@TabLayout.TabGravity int gravity) {
        if (mTabGravity != gravity) {
            mTabGravity = gravity;
            applyModeAndGravity();
        }
    }

    @Nullable
    public ColorStateList getTabTextColors() {
        return mTabTextColors;
    }

    private void setTabTextColors(@Nullable ColorStateList textColor) {
        if (mTabTextColors != textColor) {
            mTabTextColors = textColor;
            updateAllTabs();
        }
    }

    public void setTabTextColors(int normalColor, int selectedColor) {
        setTabTextColors(createColorStateList(normalColor, selectedColor));
    }

    public void setupWithViewPager(@Nullable final ViewPager viewPager) {
        if (mViewPager != null && mPageChangeListener != null) {
            mViewPager.removeOnPageChangeListener(mPageChangeListener);
        }
        if (viewPager != null) {
            final PagerAdapter adapter = viewPager.getAdapter();
            if (adapter == null) {
                throw new IllegalArgumentException("ViewPager does not have a PagerAdapter set");
            }
            mViewPager = viewPager;
            if (mPageChangeListener == null) {
                mPageChangeListener = new TabLayoutOnPageChangeListener(this);
            }
            mPageChangeListener.reset();
            viewPager.addOnPageChangeListener(mPageChangeListener);
            setOnTabSelectedListener(new ViewPagerOnTabSelectedListener(viewPager));
            setPagerAdapter(adapter, true);
        } else {
            mViewPager = null;
            setOnTabSelectedListener(null);
            setPagerAdapter(null, true);
        }
    }

    @Deprecated
    public void setTabsFromPagerAdapter(@Nullable final PagerAdapter adapter) {
        setPagerAdapter(adapter, false);
    }

    @Override
    public boolean shouldDelayChildPressedState() {
        return getTabScrollRange() > 0;
    }

    private int getTabScrollRange() {
        return Math.max(0, mTabStrip.getWidth() - getWidth() - getPaddingLeft()
                - getPaddingRight());
    }

    private void setPagerAdapter(@Nullable final PagerAdapter adapter, final boolean addObserver) {
        if (mPagerAdapter != null && mPagerAdapterObserver != null) {
            mPagerAdapter.unregisterDataSetObserver(mPagerAdapterObserver);
        }
        mPagerAdapter = adapter;
        if (addObserver && adapter != null) {
            if (mPagerAdapterObserver == null) {
                mPagerAdapterObserver = new PagerAdapterObserver();
            }
            adapter.registerDataSetObserver(mPagerAdapterObserver);
        }
        populateFromPagerAdapter();
    }

    private void populateFromPagerAdapter() {
        removeAllTabs();
        if (mPagerAdapter != null) {
            final int adapterCount = mPagerAdapter.getCount();
            for (int i = 0; i < adapterCount; i++) {
                addTab(newTab().setText(mPagerAdapter.getPageTitle(i)), false);
            }
            if (mViewPager != null && adapterCount > 0) {
                final int curItem = mViewPager.getCurrentItem();
                if (curItem != getSelectedTabPosition() && curItem < getTabCount()) {
                    selectTab(getTabAt(curItem));
                }
            }
        } else {
            removeAllTabs();
        }
    }

    private void updateAllTabs() {
        for (int i = 0, z = mTabs.size(); i < z; i++) {
            mTabs.get(i).updateView();
        }
    }

    private TabView createTabView(@NonNull final Tab tab) {
        TabView tabView = mTabViewPool != null ? mTabViewPool.acquire() : null;
        if (tabView == null) {
            tabView = new TabView(getContext());
        }
        tabView.setTab(tab);
        tabView.setFocusable(true);
        tabView.setMinimumWidth(getTabMinWidth());
        return tabView;
    }

    private void configureTab(Tab tab, int position) {
        tab.setPosition(position);
        mTabs.add(position, tab);
        final int count = mTabs.size();
        for (int i = position + 1; i < count; i++) {
            mTabs.get(i).setPosition(i);
        }
    }

    private void addTabView(Tab tab, boolean setSelected) {
        final TabView tabView = tab.mView;
        if (mTabSelectedTextSize != 0) {
            tabView.post(new Runnable() {
                @Override
                public void run() {
                    int tabWidth = tabView.getWidth();
                    String text = tabView.getText();
                    if (!TextUtils.isEmpty(text)) {
                        Paint paint = new Paint();
                        paint.setTextSize(mTabSelectedTextSize);
                        Rect rect = new Rect();
                        paint.getTextBounds(text, 0, text.length(), rect);
                        if (tabWidth - rect.width() < dpToPx(SELECTED_TAB_ADD_WIDTH)) {
                            tabWidth = rect.width() + dpToPx(SELECTED_TAB_ADD_WIDTH);
                            ViewGroup.LayoutParams layoutParams = tabView.getLayoutParams();
                            layoutParams.width = tabWidth;
                            tabView.setLayoutParams(layoutParams);
                        }
                    }
                }
            });
        }
        mTabStrip.addView(tabView, createLayoutParamsForTabs());
        if (setSelected) {
            tabView.setSelected(true);
        }
    }

    private void addTabView(Tab tab, int position, boolean setSelected) {
        final TabView tabView = tab.mView;
        mTabStrip.addView(tabView, position, createLayoutParamsForTabs());
        if (setSelected) {
            tabView.setSelected(true);
        }
    }

    @Override
    public void addView(View child) {
        addViewInternal(child);
    }

    @Override
    public void addView(View child, int index) {
        addViewInternal(child);
    }

    @Override
    public void addView(View child, ViewGroup.LayoutParams params) {
        addViewInternal(child);
    }

    @Override
    public void addView(View child, int index, ViewGroup.LayoutParams params) {
        addViewInternal(child);
    }

    private void addViewInternal(final View child) {
        if (child instanceof TabItem) {
            addTabFromItemView((TabItem) child);
        } else {
            throw new IllegalArgumentException("Only TabItem instances can be added to TabLayout");
        }
    }

    private LinearLayout.LayoutParams createLayoutParamsForTabs() {
        final LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
                LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT);
        updateTabViewLayoutParams(lp);
        return lp;
    }

    private void updateTabViewLayoutParams(LinearLayout.LayoutParams lp) {
        if (mMode == MODE_FIXED && mTabGravity == GRAVITY_FILL) {
            lp.width = 0;
            lp.weight = 1;
        } else {
            lp.width = LinearLayout.LayoutParams.WRAP_CONTENT;
            lp.weight = 0;
        }
    }

    private int dpToPx(int dps) {
        return Math.round(getResources().getDisplayMetrics().density * dps);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        final int idealHeight = dpToPx(getDefaultHeight()) + getPaddingTop() + getPaddingBottom();
        switch (MeasureSpec.getMode(heightMeasureSpec)) {
            case MeasureSpec.AT_MOST:
                heightMeasureSpec = MeasureSpec.makeMeasureSpec(
                        Math.min(idealHeight, MeasureSpec.getSize(heightMeasureSpec)),
                        MeasureSpec.EXACTLY);
                break;
            case MeasureSpec.UNSPECIFIED:
                heightMeasureSpec = MeasureSpec.makeMeasureSpec(idealHeight, MeasureSpec.EXACTLY);
                break;
        }
        final int specWidth = MeasureSpec.getSize(widthMeasureSpec);
        if (MeasureSpec.getMode(widthMeasureSpec) != MeasureSpec.UNSPECIFIED) {
            if (mPagerAdapter != null && xTabDisplayNum != 0) {
                if (mPagerAdapter.getCount() == 1 || xTabDisplayNum == 1) {
                    ((WindowManager) getContext()
                            .getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay().getMetrics(dm);
                    mTabMaxWidth = dm.widthPixels;
                } else {
                    mTabMaxWidth = mRequestedTabMaxWidth > 0
                            ? mRequestedTabMaxWidth
                            : specWidth - dpToPx(TAB_MIN_WIDTH_MARGIN);
                }
            } else {
                mTabMaxWidth = mRequestedTabMaxWidth > 0
                        ? mRequestedTabMaxWidth
                        : specWidth - dpToPx(TAB_MIN_WIDTH_MARGIN);
            }
        }
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        if (getChildCount() == 1) {
            final View child = getChildAt(0);
            boolean remeasure = false;
            switch (mMode) {
                case MODE_SCROLLABLE:
                    remeasure = child.getMeasuredWidth() < getMeasuredWidth();
                    break;
                case MODE_FIXED:
                    remeasure = child.getMeasuredWidth() != getMeasuredWidth();
                    break;
            }
            if (remeasure) {
                int childHeightMeasureSpec = getChildMeasureSpec(heightMeasureSpec, getPaddingTop()
                        + getPaddingBottom(), child.getLayoutParams().height);
                int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(
                        getMeasuredWidth(), MeasureSpec.EXACTLY);
                child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
            }
        }
    }

    private void removeTabViewAt(int position) {
        final TabView view = (TabView) mTabStrip.getChildAt(position);
        mTabStrip.removeViewAt(position);
        if (view != null) {
            view.reset();
            mTabViewPool.release(view);
        }
        requestLayout();
    }

    private void animateToTab(int newPosition) {
        if (newPosition == Tab.INVALID_POSITION) {
            return;
        }
        if (getWindowToken() == null || !ViewCompat.isLaidOut(this)
                || mTabStrip.childrenNeedLayout()) {
            setScrollPosition(newPosition, 0f, true);
            return;
        }
        final int startScrollX = getScrollX();
        final int targetScrollX = calculateScrollXForTab(newPosition, 0);
        if (startScrollX != targetScrollX) {
            if (mScrollAnimator == null) {
                mScrollAnimator = ViewUtils.createAnimator();
                mScrollAnimator.setInterpolator(AnimationUtils.FAST_OUT_SLOW_IN_INTERPOLATOR);
                mScrollAnimator.setDuration(ANIMATION_DURATION);
                mScrollAnimator.setUpdateListener(new ValueAnimatorCompat.AnimatorUpdateListener() {
                    @Override
                    public void onAnimationUpdate(ValueAnimatorCompat animator) {
                        scrollTo(animator.getAnimatedIntValue(), 0);
                    }
                });
            }
            mScrollAnimator.setIntValues(startScrollX, targetScrollX);
            mScrollAnimator.start();
        }
        mTabStrip.animateIndicatorToPosition(newPosition, ANIMATION_DURATION);
    }

    private void setSelectedTabView(int position) {
        final int tabCount = mTabStrip.getChildCount();
        if (position < tabCount && !mTabStrip.getChildAt(position).isSelected()) {
            for (int i = 0; i < tabCount; i++) {
                final View child = mTabStrip.getChildAt(i);
                child.setSelected(i == position);
            }
        }
    }

    private void selectTab(Tab tab) {
        selectTab(tab, true);
    }

    private void selectTab(Tab tab, boolean updateIndicator) {
        if (mSelectedTab == tab) {
            if (mSelectedTab != null) {
                if (mOnTabSelectedListener != null) {
                    mOnTabSelectedListener.onTabReselected(mSelectedTab);
                }
                for (OnTabSelectedListener onTabSelectedListener : mOnTabSelectedListenerList) {
                    onTabSelectedListener.onTabReselected(mSelectedTab);
                }
                animateToTab(tab.getPosition());
            }
        } else {
            if (updateIndicator) {
                final int newPosition = tab != null ? tab.getPosition() : Tab.INVALID_POSITION;
                if (newPosition != Tab.INVALID_POSITION) {
                    setSelectedTabView(newPosition);
                }
                if ((mSelectedTab == null || mSelectedTab.getPosition() == Tab.INVALID_POSITION)
                        && newPosition != Tab.INVALID_POSITION) {
                    setScrollPosition(newPosition, 0f, true);
                } else {
                    animateToTab(newPosition);
                }
            }
            if (mSelectedTab != null && mOnTabSelectedListener != null) {
                mOnTabSelectedListener.onTabUnselected(mSelectedTab);
            }
            for (OnTabSelectedListener onTabSelectedListener : mOnTabSelectedListenerList) {
                onTabSelectedListener.onTabUnselected(mSelectedTab);
            }
            mSelectedTab = tab;
            if (mSelectedTab != null && mOnTabSelectedListener != null) {
                mOnTabSelectedListener.onTabSelected(mSelectedTab);
            }
            for (OnTabSelectedListener onTabSelectedListener : mOnTabSelectedListenerList) {
                onTabSelectedListener.onTabSelected(mSelectedTab);
            }
        }
    }

    private int calculateScrollXForTab(int position, float positionOffset) {
        if (mMode == MODE_SCROLLABLE) {
            final View selectedChild = mTabStrip.getChildAt(position);
            final View nextChild = position + 1 < mTabStrip.getChildCount()
                    ? mTabStrip.getChildAt(position + 1)
                    : null;
            final int selectedWidth = selectedChild != null ? selectedChild.getWidth() : 0;
            final int nextWidth = nextChild != null ? nextChild.getWidth() : 0;
            return selectedChild.getLeft()
                    + ((int) ((selectedWidth + nextWidth) * positionOffset * 0.5f))
                    + (selectedChild.getWidth() / 2)
                    - (getWidth() / 2);
        }
        return 0;
    }

    private void applyModeAndGravity() {
        int paddingStart = 0;
        if (mMode == MODE_SCROLLABLE) {
            paddingStart = Math.max(0, mContentInsetStart - mTabPaddingStart);
        }
        ViewCompat.setPaddingRelative(mTabStrip, paddingStart, 0, 0, 0);
        switch (mMode) {
            case MODE_FIXED:
                mTabStrip.setGravity(Gravity.CENTER_HORIZONTAL);
                break;
            case MODE_SCROLLABLE:
                mTabStrip.setGravity(GravityCompat.START);
                break;
        }
        updateTabViews(true);
    }

    private void updateTabViews(final boolean requestLayout) {
        for (int i = 0; i < mTabStrip.getChildCount(); i++) {
            View child = mTabStrip.getChildAt(i);
            child.setMinimumWidth(getTabMinWidth());
            updateTabViewLayoutParams((LinearLayout.LayoutParams) child.getLayoutParams());
            if (requestLayout) {
                child.requestLayout();
            }
        }
    }

    private int getDefaultHeight() {
        boolean hasIconAndText = false;
        for (int i = 0, count = mTabs.size(); i < count; i++) {
            Tab tab = mTabs.get(i);
            if (tab != null && tab.getIcon() != null && !TextUtils.isEmpty(tab.getText())) {
                hasIconAndText = true;
                break;
            }
        }
        return hasIconAndText ? DEFAULT_HEIGHT_WITH_TEXT_ICON : DEFAULT_HEIGHT;
    }

    private int getTabMinWidth() {
        DisplayMetrics dm = new DisplayMetrics();
        ((WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay().getMetrics(dm);
        int width = dm.widthPixels;
        if (mPagerAdapter != null && xTabDisplayNum != 0) {
            if (mPagerAdapter.getCount() == 1 || xTabDisplayNum == 1) {
                return width;
            } else if (mPagerAdapter.getCount() < xTabDisplayNum) {
                return width / mPagerAdapter.getCount();
            } else {
                return width / xTabDisplayNum;
            }
        }
        if (xTabDisplayNum != 0) {
            return width / xTabDisplayNum;
        }
        if (mRequestedTabMinWidth != INVALID_WIDTH) {
            return mRequestedTabMinWidth;
        }
        return mMode == MODE_SCROLLABLE ? mScrollableTabMinWidth : 0;
    }

    @Override
    public LayoutParams generateLayoutParams(AttributeSet attrs) {
        return generateDefaultLayoutParams();
    }

    private int getTabMaxWidth() {
        return mTabMaxWidth;
    }

    public interface OnTabSelectedListener {
        void onTabSelected(Tab tab);

        void onTabUnselected(Tab tab);

        void onTabReselected(Tab tab);
    }

    public static final class Tab {
        static final int INVALID_POSITION = -1;
        private Object mTag;
        private Drawable mIcon;
        private CharSequence mText;
        private CharSequence mContentDesc;
        private int mPosition = INVALID_POSITION;
        private View mCustomView;
        private XTabLayout mParent;
        private TabView mView;

        private Tab() {
        }

        @Nullable
        public Object getTag() {
            return mTag;
        }

        @NonNull
        public Tab setTag(@Nullable Object tag) {
            mTag = tag;
            return this;
        }

        int getTextWidth() {
            return mView.getTextWidth();
        }

        @Nullable
        public View getCustomView() {
            return mCustomView;
        }

        @NonNull
        public Tab setCustomView(@Nullable View view) {
            mCustomView = view;
            updateView();
            return this;
        }

        @NonNull
        Tab setCustomView(@LayoutRes int resId) {
            final LayoutInflater inflater = LayoutInflater.from(mView.getContext());
            return setCustomView(inflater.inflate(resId, mView, false));
        }

        @Nullable
        Drawable getIcon() {
            return mIcon;
        }

        @NonNull
        Tab setIcon(@Nullable Drawable icon) {
            mIcon = icon;
            updateView();
            return this;
        }

        @SuppressLint("RestrictedApi")
        @NonNull
        public Tab setIcon(@DrawableRes int resId) {
            if (mParent == null) {
                throw new IllegalArgumentException("Tab not attached to a TabLayout");
            }
            return setIcon(get().getDrawable(mParent.getContext(), resId));
        }

        public int getPosition() {
            return mPosition;
        }

        void setPosition(int position) {
            mPosition = position;
        }

        @Nullable
        public CharSequence getText() {
            return mText;
        }

        @NonNull
        public Tab setText(@Nullable CharSequence text) {
            mText = text;
            updateView();
            return this;
        }

        @NonNull
        public Tab setText(@StringRes int resId) {
            if (mParent == null) {
                throw new IllegalArgumentException("Tab not attached to a TabLayout");
            }
            return setText(mParent.getResources().getText(resId));
        }

        public void select() {
            if (mParent == null) {
                throw new IllegalArgumentException("Tab not attached to a TabLayout");
            }
            mParent.selectTab(this);
        }

        public boolean isSelected() {
            if (mParent == null) {
                throw new IllegalArgumentException("Tab not attached to a TabLayout");
            }
            return mParent.getSelectedTabPosition() == mPosition;
        }

        @Nullable
        CharSequence getContentDescription() {
            return mContentDesc;
        }

        @NonNull
        public Tab setContentDescription(@StringRes int resId) {
            if (mParent == null) {
                throw new IllegalArgumentException("Tab not attached to a TabLayout");
            }
            return setContentDescription(mParent.getResources().getText(resId));
        }

        @NonNull
        Tab setContentDescription(@Nullable CharSequence contentDesc) {
            mContentDesc = contentDesc;
            updateView();
            return this;
        }

        private void updateView() {
            if (mView != null) {
                mView.update();
            }
        }

        private void reset() {
            mParent = null;
            mView = null;
            mTag = null;
            mIcon = null;
            mText = null;
            mContentDesc = null;
            mPosition = INVALID_POSITION;
            mCustomView = null;
        }
    }

    static class TabLayoutOnPageChangeListener implements ViewPager.OnPageChangeListener {
        private final WeakReference<XTabLayout> mTabLayoutRef;
        private int mPreviousScrollState;
        private int mScrollState;

        TabLayoutOnPageChangeListener(XTabLayout tabLayout) {
            mTabLayoutRef = new WeakReference<>(tabLayout);
        }

        @Override
        public void onPageScrollStateChanged(int state) {
            mPreviousScrollState = mScrollState;
            mScrollState = state;
        }

        @Override
        public void onPageScrolled(int position, float positionOffset,
                                   int positionOffsetPixels) {
            final XTabLayout tabLayout = mTabLayoutRef.get();
            if (tabLayout != null) {
                final boolean updateText = mScrollState != SCROLL_STATE_SETTLING ||
                        mPreviousScrollState == SCROLL_STATE_DRAGGING;
                final boolean updateIndicator = !(mScrollState == SCROLL_STATE_SETTLING
                        && mPreviousScrollState == SCROLL_STATE_IDLE);
                tabLayout.setScrollPosition(position, positionOffset, updateText, updateIndicator);
            }
        }

        @Override
        public void onPageSelected(int position) {
            final XTabLayout tabLayout = mTabLayoutRef.get();
            if (tabLayout != null && tabLayout.getSelectedTabPosition() != position) {
                final boolean updateIndicator = mScrollState == SCROLL_STATE_IDLE
                        || (mScrollState == SCROLL_STATE_SETTLING
                        && mPreviousScrollState == SCROLL_STATE_IDLE);
                tabLayout.selectTab(tabLayout.getTabAt(position), updateIndicator);
            }
        }

        private void reset() {
            mPreviousScrollState = mScrollState = SCROLL_STATE_IDLE;
        }
    }

    public static class ViewPagerOnTabSelectedListener implements OnTabSelectedListener {
        private final ViewPager mViewPager;

        ViewPagerOnTabSelectedListener(ViewPager viewPager) {
            mViewPager = viewPager;
        }

        @Override
        public void onTabSelected(Tab tab) {
            mViewPager.setCurrentItem(tab.getPosition());
        }

        @Override
        public void onTabUnselected(Tab tab) {
        }

        @Override
        public void onTabReselected(Tab tab) {
        }
    }

    static class ViewUtils {
        static final ValueAnimatorCompat.Creator DEFAULT_ANIMATOR_CREATOR
                = new ValueAnimatorCompat.Creator() {
            @Override
            public ValueAnimatorCompat createAnimator() {
                return new ValueAnimatorCompat(Build.VERSION.SDK_INT >= 12
                        ? new ValueAnimatorCompatImplHoneycombMr1()
                        : new ValueAnimatorCompatImplEclairMr1());
            }
        };
        private static final ViewUtilsImpl IMPL;

        static {
            final int version = Build.VERSION.SDK_INT;
            if (version >= 21) {
                IMPL = new ViewUtilsImplLollipop();
            } else {
                IMPL = new ViewUtilsImplBase();
            }
        }

        static void setBoundsViewOutlineProvider(View view) {
            IMPL.setBoundsViewOutlineProvider(view);
        }

        static ValueAnimatorCompat createAnimator() {
            return DEFAULT_ANIMATOR_CREATOR.createAnimator();
        }

        private interface ViewUtilsImpl {
            void setBoundsViewOutlineProvider(View view);
        }

        private static class ViewUtilsImplBase implements ViewUtilsImpl {
            @Override
            public void setBoundsViewOutlineProvider(View view) {
            }
        }

        private static class ViewUtilsImplLollipop implements ViewUtilsImpl {
            @Override
            public void setBoundsViewOutlineProvider(View view) {
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                    view.setOutlineProvider(ViewOutlineProvider.BOUNDS);
                }
            }
        }
    }

    static class ValueAnimatorCompat {
        private final ValueAnimatorCompat.Impl mImpl;

        ValueAnimatorCompat(ValueAnimatorCompat.Impl impl) {
            mImpl = impl;
        }

        void start() {
            mImpl.start();
        }

        boolean isRunning() {
            return mImpl.isRunning();
        }

        void setInterpolator(Interpolator interpolator) {
            mImpl.setInterpolator(interpolator);
        }

        void setUpdateListener(final ValueAnimatorCompat.AnimatorUpdateListener updateListener) {
            if (updateListener != null) {
                mImpl.setUpdateListener(new ValueAnimatorCompat.Impl.AnimatorUpdateListenerProxy() {
                    @Override
                    public void onAnimationUpdate() {
                        updateListener.onAnimationUpdate(ValueAnimatorCompat.this);
                    }
                });
            } else {
                mImpl.setUpdateListener(null);
            }
        }

        void setListener(final ValueAnimatorCompat.AnimatorListener listener) {
            if (listener != null) {
                mImpl.setListener(new ValueAnimatorCompat.Impl.AnimatorListenerProxy() {
                    @Override
                    public void onAnimationStart() {
                        listener.onAnimationStart(ValueAnimatorCompat.this);
                    }

                    @Override
                    public void onAnimationEnd() {
                        listener.onAnimationEnd(ValueAnimatorCompat.this);
                    }

                    @Override
                    public void onAnimationCancel() {
                        listener.onAnimationCancel(ValueAnimatorCompat.this);
                    }
                });
            } else {
                mImpl.setListener(null);
            }
        }

        void setIntValues(int from, int to) {
            mImpl.setIntValues(from, to);
        }

        int getAnimatedIntValue() {
            return mImpl.getAnimatedIntValue();
        }

        void setFloatValues(float from, float to) {
            mImpl.setFloatValues(from, to);
        }

        public float getAnimatedFloatValue() {
            return mImpl.getAnimatedFloatValue();
        }

        void cancel() {
            mImpl.cancel();
        }

        float getAnimatedFraction() {
            return mImpl.getAnimatedFraction();
        }

        public void end() {
            mImpl.end();
        }

        long getDuration() {
            return mImpl.getDuration();
        }

        void setDuration(int duration) {
            mImpl.setDuration(duration);
        }

        interface AnimatorUpdateListener {
            void onAnimationUpdate(ValueAnimatorCompat animator);
        }

        interface AnimatorListener {
            void onAnimationStart(ValueAnimatorCompat animator);

            void onAnimationEnd(ValueAnimatorCompat animator);

            void onAnimationCancel(ValueAnimatorCompat animator);
        }

        interface Creator {
            ValueAnimatorCompat createAnimator();
        }

        static class AnimatorListenerAdapter implements ValueAnimatorCompat.AnimatorListener {
            @Override
            public void onAnimationStart(ValueAnimatorCompat animator) {
            }

            @Override
            public void onAnimationEnd(ValueAnimatorCompat animator) {
            }

            @Override
            public void onAnimationCancel(ValueAnimatorCompat animator) {
            }
        }

        static abstract class Impl {
            abstract void start();

            abstract boolean isRunning();

            abstract void setInterpolator(Interpolator interpolator);

            abstract void setListener(ValueAnimatorCompat.Impl.AnimatorListenerProxy listener);

            abstract void setUpdateListener(ValueAnimatorCompat.Impl.AnimatorUpdateListenerProxy updateListener);

            abstract void setIntValues(int from, int to);

            abstract int getAnimatedIntValue();

            abstract void setFloatValues(float from, float to);

            abstract float getAnimatedFloatValue();

            abstract void cancel();

            abstract float getAnimatedFraction();

            abstract void end();

            abstract long getDuration();

            abstract void setDuration(int duration);

            interface AnimatorUpdateListenerProxy {
                void onAnimationUpdate();
            }

            interface AnimatorListenerProxy {
                void onAnimationStart();

                void onAnimationEnd();

                void onAnimationCancel();
            }
        }
    }

    static class AnimationUtils {
        static final Interpolator LINEAR_INTERPOLATOR = new LinearInterpolator();
        static final Interpolator FAST_OUT_SLOW_IN_INTERPOLATOR = new FastOutSlowInInterpolator();
        static final Interpolator FAST_OUT_LINEAR_IN_INTERPOLATOR = new FastOutLinearInInterpolator();
        static final Interpolator LINEAR_OUT_SLOW_IN_INTERPOLATOR = new LinearOutSlowInInterpolator();
        static final Interpolator DECELERATE_INTERPOLATOR = new DecelerateInterpolator();

        static float lerp(float startValue, float endValue, float fraction) {
            return startValue + (fraction * (endValue - startValue));
        }

        static int lerp(int startValue, int endValue, float fraction) {
            return startValue + Math.round(fraction * (endValue - startValue));
        }
    }

    static class ValueAnimatorCompatImplEclairMr1 extends XTabLayout.ValueAnimatorCompat.Impl {
        private static final int HANDLER_DELAY = 10;
        private static final int DEFAULT_DURATION = 200;
        private static final Handler sHandler = new Handler(Looper.getMainLooper());
        private final int[] mIntValues = new int[2];
        private final float[] mFloatValues = new float[2];
        private long mStartTime;
        private boolean mIsRunning;
        private int mDuration = DEFAULT_DURATION;
        private Interpolator mInterpolator;
        private AnimatorListenerProxy mListener;
        private AnimatorUpdateListenerProxy mUpdateListener;
        private float mAnimatedFraction;
        private final Runnable mRunnable = new Runnable() {
            public void run() {
                update();
            }
        };

        @Override
        public void start() {
            if (mIsRunning) {
                return;
            }
            if (mInterpolator == null) {
                mInterpolator = new AccelerateDecelerateInterpolator();
            }
            mStartTime = SystemClock.uptimeMillis();
            mIsRunning = true;
            if (mListener != null) {
                mListener.onAnimationStart();
            }
            sHandler.postDelayed(mRunnable, HANDLER_DELAY);
        }

        @Override
        public boolean isRunning() {
            return mIsRunning;
        }

        @Override
        public void setInterpolator(Interpolator interpolator) {
            mInterpolator = interpolator;
        }

        @Override
        public void setListener(AnimatorListenerProxy listener) {
            mListener = listener;
        }

        @Override
        public void setUpdateListener(AnimatorUpdateListenerProxy updateListener) {
            mUpdateListener = updateListener;
        }

        @Override
        public void setIntValues(int from, int to) {
            mIntValues[0] = from;
            mIntValues[1] = to;
        }

        @Override
        public int getAnimatedIntValue() {
            return AnimationUtils.lerp(mIntValues[0], mIntValues[1], getAnimatedFraction());
        }

        @Override
        public void setFloatValues(float from, float to) {
            mFloatValues[0] = from;
            mFloatValues[1] = to;
        }

        @Override
        public float getAnimatedFloatValue() {
            return AnimationUtils.lerp(mFloatValues[0], mFloatValues[1], getAnimatedFraction());
        }

        @Override
        public void cancel() {
            mIsRunning = false;
            sHandler.removeCallbacks(mRunnable);
            if (mListener != null) {
                mListener.onAnimationCancel();
            }
        }

        @Override
        float getAnimatedFraction() {
            return mAnimatedFraction;
        }

        @Override
        public void end() {
            if (mIsRunning) {
                mIsRunning = false;
                sHandler.removeCallbacks(mRunnable);
                mAnimatedFraction = 1f;
                if (mUpdateListener != null) {
                    mUpdateListener.onAnimationUpdate();
                }
                if (mListener != null) {
                    mListener.onAnimationEnd();
                }
            }
        }

        @Override
        public long getDuration() {
            return mDuration;
        }

        @Override
        public void setDuration(int duration) {
            mDuration = duration;
        }

        private void update() {
            if (mIsRunning) {
                final long elapsed = SystemClock.uptimeMillis() - mStartTime;
                final float linearFraction = elapsed / (float) mDuration;
                mAnimatedFraction = mInterpolator != null
                        ? mInterpolator.getInterpolation(linearFraction)
                        : linearFraction;
                if (mUpdateListener != null) {
                    mUpdateListener.onAnimationUpdate();
                }
                if (SystemClock.uptimeMillis() >= (mStartTime + mDuration)) {
                    mIsRunning = false;
                    if (mListener != null) {
                        mListener.onAnimationEnd();
                    }
                }
            }
            if (mIsRunning) {
                sHandler.postDelayed(mRunnable, HANDLER_DELAY);
            }
        }
    }

    static class ValueAnimatorCompatImplHoneycombMr1 extends XTabLayout.ValueAnimatorCompat.Impl {
        final ValueAnimator mValueAnimator;

        ValueAnimatorCompatImplHoneycombMr1() {
            mValueAnimator = new ValueAnimator();
        }

        @Override
        public void start() {
            mValueAnimator.start();
        }

        @Override
        public boolean isRunning() {
            return mValueAnimator.isRunning();
        }

        @Override
        public void setInterpolator(Interpolator interpolator) {
            mValueAnimator.setInterpolator(interpolator);
        }

        @Override
        public void setUpdateListener(final AnimatorUpdateListenerProxy updateListener) {
            mValueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator valueAnimator) {
                    updateListener.onAnimationUpdate();
                }
            });
        }

        @Override
        public void setListener(final AnimatorListenerProxy listener) {
            mValueAnimator.addListener(new AnimatorListenerAdapter() {
                @Override
                public void onAnimationStart(Animator animator) {
                    listener.onAnimationStart();
                }

                @Override
                public void onAnimationEnd(Animator animator) {
                    listener.onAnimationEnd();
                }

                @Override
                public void onAnimationCancel(Animator animator) {
                    listener.onAnimationCancel();
                }
            });
        }

        @Override
        public void setIntValues(int from, int to) {
            mValueAnimator.setIntValues(from, to);
        }

        @Override
        public int getAnimatedIntValue() {
            return (int) mValueAnimator.getAnimatedValue();
        }

        @Override
        public void setFloatValues(float from, float to) {
            mValueAnimator.setFloatValues(from, to);
        }

        @Override
        public float getAnimatedFloatValue() {
            return (float) mValueAnimator.getAnimatedValue();
        }

        @Override
        public void cancel() {
            mValueAnimator.cancel();
        }

        @Override
        public float getAnimatedFraction() {
            return mValueAnimator.getAnimatedFraction();
        }

        @Override
        public void end() {
            mValueAnimator.end();
        }

        @Override
        public long getDuration() {
            return mValueAnimator.getDuration();
        }

        @Override
        public void setDuration(int duration) {
            mValueAnimator.setDuration(duration);
        }
    }

    class TabView extends LinearLayout implements OnLongClickListener {
        private Tab mTab;
        private TextView mTextView;
        private ImageView mIconView;
        private View mCustomView;
        private TextView mCustomTextView;
        private ImageView mCustomIconView;
        private int mDefaultMaxLines = 2;

        public TabView(Context context) {
            super(context);
            ViewCompat.setPaddingRelative(this, mTabPaddingStart, mTabPaddingTop,
                    mTabPaddingEnd, mTabPaddingBottom);
            setGravity(Gravity.CENTER);
            setOrientation(VERTICAL);
            setClickable(true);
        }

        String getText() {
            return mTextView.getText().toString();
        }

        int getTextWidth() {
            if (TextUtils.isEmpty(mTextView.getText().toString())) {
                return 0;
            }
            Rect rect = new Rect();
            String content = mTextView.getText().toString();
            mTextView.getPaint().getTextBounds(content, 0, content.length(), rect);
            return rect.width();
        }

        @Override
        public boolean performClick() {
            final boolean value = super.performClick();
            if (mTab != null) {
                mTab.select();
                return true;
            } else {
                return value;
            }
        }

        @Override
        public void setSelected(boolean selected) {
            final boolean changed = (isSelected() != selected);
            super.setSelected(selected);
            if (!selected) {
                if (xTabBackgroundColor != 0) {
                    setBackgroundColor(xTabBackgroundColor);
                }
                mTextView.setTextSize(TypedValue.COMPLEX_UNIT_SP, mTabTextSize);
                if (xTabTextBold) {
                    mTextView.setTypeface(Typeface.defaultFromStyle(Typeface.BOLD));
                } else {
                    mTextView.setTypeface(Typeface.defaultFromStyle(Typeface.NORMAL));
                }
            }
            if (changed && selected) {
                if (xTabSelectedBackgroundColor != 0) {
                    setBackgroundColor(xTabSelectedBackgroundColor);
                }
                sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED);
                if (mTextView != null) {
                    mTextView.setSelected(selected);
                    if (mTabSelectedTextSize != 0) {
                        mTextView.setTextSize(TypedValue.COMPLEX_UNIT_SP, mTabSelectedTextSize);
                        if (xTabTextSelectedBold) {
                            mTextView.setTypeface(Typeface.defaultFromStyle(Typeface.BOLD));
                        } else {
                            mTextView.setTypeface(Typeface.defaultFromStyle(Typeface.NORMAL));
                        }
                    }
                }
                if (mIconView != null) {
                    mIconView.setSelected(selected);
                }
            }
        }

        @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
        @Override
        public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
            super.onInitializeAccessibilityEvent(event);
            event.setClassName(ActionBar.Tab.class.getName());
        }

        @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
        @Override
        public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
            super.onInitializeAccessibilityNodeInfo(info);
            info.setClassName(ActionBar.Tab.class.getName());
        }

        @Override
        public void onMeasure(final int origWidthMeasureSpec, final int origHeightMeasureSpec) {
            final int specWidthSize = MeasureSpec.getSize(origWidthMeasureSpec);
            final int specWidthMode = MeasureSpec.getMode(origWidthMeasureSpec);
            final int maxWidth = getTabMaxWidth();
            final int widthMeasureSpec;
            if (maxWidth > 0 && (specWidthMode == MeasureSpec.UNSPECIFIED
                    || specWidthSize > maxWidth)) {
                widthMeasureSpec = MeasureSpec.makeMeasureSpec(mTabMaxWidth, MeasureSpec.AT_MOST);
            } else {
                widthMeasureSpec = origWidthMeasureSpec;
            }
            super.onMeasure(widthMeasureSpec, origHeightMeasureSpec);
            if (mTextView != null) {
                final Resources res = getResources();
                float textSize = mTabTextSize;
                int maxLines = mDefaultMaxLines;
                if (mIconView != null && mIconView.getVisibility() == VISIBLE) {
                    maxLines = 1;
                } else if (mTextView != null && mTextView.getLineCount() > 1) {
                    textSize = mTabTextMultiLineSize;
                }
                final float curTextSize = mTextView.getTextSize();
                final int curLineCount = mTextView.getLineCount();
                final int curMaxLines = TextViewCompat.getMaxLines(mTextView);
                if (textSize != curTextSize || (curMaxLines >= 0 && maxLines != curMaxLines)) {
                    boolean updateTextView = true;
                    if (mMode == MODE_FIXED && textSize > curTextSize && curLineCount == 1) {
                        final Layout layout = mTextView.getLayout();
                        if (layout == null
                                || approximateLineWidth(layout, 0, textSize) > layout.getWidth()) {
                            updateTextView = false;
                        }
                    }
                    if (updateTextView) {
                        if (mTextView.isSelected() && mTabSelectedTextSize != 0) {
                            mTextView.setTextSize(TypedValue.COMPLEX_UNIT_SP, mTabSelectedTextSize);
                        } else {
                            mTextView.setTextSize(TypedValue.COMPLEX_UNIT_SP, mTabTextSize);
                        }
                        mTextView.setMaxLines(maxLines);
                        super.onMeasure(widthMeasureSpec, origHeightMeasureSpec);
                    }
                }
            }
        }

        private void reset() {
            setTab(null);
            setSelected(false);
        }

        final void update() {
            final Tab tab = mTab;
            final View custom = tab != null ? tab.getCustomView() : null;
            if (custom != null) {
                final ViewParent customParent = custom.getParent();
                if (customParent != this) {
                    if (customParent != null) {
                        ((ViewGroup) customParent).removeView(custom);
                    }
                    addView(custom);
                }
                mCustomView = custom;
                if (mTextView != null) {
                    mTextView.setVisibility(GONE);
                }
                if (mIconView != null) {
                    mIconView.setVisibility(GONE);
                    mIconView.setImageDrawable(null);
                }
                mCustomTextView = custom.findViewById(android.R.id.text1);
                if (mCustomTextView != null) {
                    mDefaultMaxLines = TextViewCompat.getMaxLines(mCustomTextView);
                }
                mCustomIconView = custom.findViewById(android.R.id.icon);
            } else {
                if (mCustomView != null) {
                    removeView(mCustomView);
                    mCustomView = null;
                }
                mCustomTextView = null;
                mCustomIconView = null;
            }
            if (mCustomView == null) {
                if (mIconView == null) {
                    ImageView iconView = (ImageView) LayoutInflater.from(getContext())
                            .inflate(R.layout.design_layout_tab_icon, this, false);
                    addView(iconView, 0);
                    mIconView = iconView;
                }
                if (mTextView == null) {
                    TextView textView = (TextView) LayoutInflater.from(getContext())
                            .inflate(R.layout.design_layout_tab_text, this, false);
                    addView(textView);
                    mTextView = textView;
                    mDefaultMaxLines = TextViewCompat.getMaxLines(mTextView);
                }
                mTextView.setTextAppearance(getContext(), mTabTextAppearance);
                if (mTabTextColors != null) {
                    mTextView.setTextColor(mTabTextColors);
                }
                updateTextAndIcon(mTextView, mIconView);
            } else {
                if (mCustomTextView != null || mCustomIconView != null) {
                    updateTextAndIcon(mCustomTextView, mCustomIconView);
                }
            }
        }

        private void updateTextAndIcon(@Nullable final TextView textView,
                                       @Nullable final ImageView iconView) {
            final Drawable icon = mTab != null ? mTab.getIcon() : null;
            final CharSequence text = mTab != null ? mTab.getText() : null;
            final CharSequence contentDesc = mTab != null ? mTab.getContentDescription() : null;
            if (iconView != null) {
                if (icon != null) {
                    iconView.setImageDrawable(icon);
                    iconView.setVisibility(VISIBLE);
                    setVisibility(VISIBLE);
                } else {
                    iconView.setVisibility(GONE);
                    iconView.setImageDrawable(null);
                }
                iconView.setContentDescription(contentDesc);
            }
            final boolean hasText = !TextUtils.isEmpty(text);
            if (textView != null) {
                if (hasText) {
                    textView.setAllCaps(xTabTextAllCaps);
                    textView.setText(text);
                    textView.setVisibility(VISIBLE);
                    setVisibility(VISIBLE);
                } else {
                    textView.setVisibility(GONE);
                    textView.setText(null);
                }
                textView.setContentDescription(contentDesc);
            }
            if (iconView != null) {
                MarginLayoutParams lp = ((MarginLayoutParams) iconView.getLayoutParams());
                int bottomMargin = 0;
                if (hasText && iconView.getVisibility() == VISIBLE) {
                    bottomMargin = dpToPx(DEFAULT_GAP_TEXT_ICON);
                }
                if (bottomMargin != lp.bottomMargin) {
                    lp.bottomMargin = bottomMargin;
                    iconView.requestLayout();
                }
            }
            if (!hasText && !TextUtils.isEmpty(contentDesc)) {
                setOnLongClickListener(this);
            } else {
                setOnLongClickListener(null);
                setLongClickable(false);
            }
        }

        @Override
        public boolean onLongClick(View v) {
            final int[] screenPos = new int[2];
            getLocationOnScreen(screenPos);
            final Context context = getContext();
            final int width = getWidth();
            final int height = getHeight();
            final int screenWidth = context.getResources().getDisplayMetrics().widthPixels;
            Toast cheatSheet = Toast.makeText(context, mTab.getContentDescription(),
                    Toast.LENGTH_SHORT);
            cheatSheet.setGravity(Gravity.TOP | Gravity.CENTER_HORIZONTAL,
                    (screenPos[0] + width / 2) - screenWidth / 2, height);
            cheatSheet.show();
            return true;
        }

        public Tab getTab() {
            return mTab;
        }

        private void setTab(@Nullable final Tab tab) {
            if (tab != mTab) {
                mTab = tab;
                update();
            }
        }

        private float approximateLineWidth(Layout layout, int line, float textSize) {
            return layout.getLineWidth(line) * (textSize / layout.getPaint().getTextSize());
        }
    }

    private class SlidingTabStrip extends LinearLayout {
        private final Paint mSelectedIndicatorPaint;
        private int mSelectedIndicatorHeight;
        private int mSelectedIndicatorWidth;
        private int mSelectedPosition = -1;
        private float mSelectionOffset;
        private int mIndicatorLeft = -1;
        private int mIndicatorRight = -1;
        private ValueAnimatorCompat mIndicatorAnimator;

        SlidingTabStrip(Context context) {
            super(context);
            setWillNotDraw(false);
            mSelectedIndicatorPaint = new Paint();
        }

        void setSelectedIndicatorColor(int color) {
            if (mSelectedIndicatorPaint.getColor() != color) {
                mSelectedIndicatorPaint.setColor(color);
                ViewCompat.postInvalidateOnAnimation(this);
            }
        }

        void setSelectedIndicatorHeight(int height) {
            if (mSelectedIndicatorHeight != height) {
                mSelectedIndicatorHeight = height;
                ViewCompat.postInvalidateOnAnimation(this);
            }
        }

        public int getmSelectedIndicatorWidth() {
            return mSelectedIndicatorWidth;
        }

        void setmSelectedIndicatorWidth(int width) {
            if (mSelectedIndicatorWidth != width) {
                mSelectedIndicatorWidth = width;
                ViewCompat.postInvalidateOnAnimation(this);
            }
        }

        boolean childrenNeedLayout() {
            for (int i = 0, z = getChildCount(); i < z; i++) {
                final View child = getChildAt(i);
                if (child.getWidth() <= 0) {
                    return true;
                }
            }
            return false;
        }

        void setIndicatorPositionFromTabPosition(int position, float positionOffset) {
            if (mIndicatorAnimator != null && mIndicatorAnimator.isRunning()) {
                mIndicatorAnimator.cancel();
            }
            mSelectedPosition = position;
            mSelectionOffset = positionOffset;
            updateIndicatorPosition();
        }

        float getIndicatorPosition() {
            return mSelectedPosition + mSelectionOffset;
        }

        @Override
        protected void onMeasure(final int widthMeasureSpec, final int heightMeasureSpec) {
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
            if (MeasureSpec.getMode(widthMeasureSpec) != MeasureSpec.EXACTLY) {
                return;
            }
            if (mMode == MODE_FIXED && mTabGravity == GRAVITY_CENTER) {
                final int count = getChildCount();
                int largestTabWidth = 0;
                for (int i = 0; i < count; i++) {
                    View child = getChildAt(i);
                    if (child.getVisibility() == VISIBLE) {
                        largestTabWidth = Math.max(largestTabWidth, child.getMeasuredWidth());
                    }
                }
                if (largestTabWidth <= 0) {
                    return;
                }
                final int gutter = dpToPx(FIXED_WRAP_GUTTER_MIN);
                boolean remeasure = false;
                if (largestTabWidth * count <= getMeasuredWidth() - gutter * 2) {
                    for (int i = 0; i < count; i++) {
                        final LayoutParams lp =
                                (LayoutParams) getChildAt(i).getLayoutParams();
                        if (lp.width != largestTabWidth || lp.weight != 0) {
                            lp.width = largestTabWidth;
                            lp.weight = 0;
                            remeasure = true;
                        }
                    }
                } else {
                    mTabGravity = GRAVITY_FILL;
                    updateTabViews(false);
                    remeasure = true;
                }
                if (remeasure) {
                    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
                }
            }
        }

        @Override
        protected void onLayout(boolean changed, int l, int t, int r, int b) {
            super.onLayout(changed, l, t, r, b);
            if (mIndicatorAnimator != null && mIndicatorAnimator.isRunning()) {
                mIndicatorAnimator.cancel();
                final long duration = mIndicatorAnimator.getDuration();
                animateIndicatorToPosition(mSelectedPosition,
                        Math.round((1f - mIndicatorAnimator.getAnimatedFraction()) * duration));
            } else {
                updateIndicatorPosition();
            }
        }

        private void updateIndicatorPosition() {
            final View selectedTitle = getChildAt(mSelectedPosition);
            int left, right;
            if (selectedTitle != null && selectedTitle.getWidth() > 0) {
                left = selectedTitle.getLeft();
                right = selectedTitle.getRight();
                int haftWidth = 0;
                if (mSelectedIndicatorWidth == 0
                        && !xTabDividerWidthWidthText) mSelectedIndicatorWidth = maxWidth;
                if (mSelectedIndicatorWidth != 0) {
                    int maxWidth = mIndicatorRight - mIndicatorLeft;
                    if (maxWidth > mSelectedIndicatorWidth) {
                        haftWidth = (maxWidth - mSelectedIndicatorWidth) / 2;
                        left += haftWidth;
                        right -= haftWidth;
                    }
                }
                if (mSelectionOffset > 0f && mSelectedPosition < getChildCount() - 1) {
                    View nextTitle = getChildAt(mSelectedPosition + 1);
                    int nextLeft = nextTitle.getLeft() + haftWidth;
                    int nextRight = nextTitle.getRight() - haftWidth;
                    left = (int) (mSelectionOffset * nextLeft +
                            (1.0f - mSelectionOffset) * left);
                    right = (int) (mSelectionOffset * nextRight +
                            (1.0f - mSelectionOffset) * right);
                }
            } else {
                left = right = -1;
            }
            setIndicatorPosition(left, right);
        }

        private void setIndicatorPosition(int left, int right) {
            left = left + mTabPaddingStart;
            right = right - mTabPaddingEnd;
            if (left != mIndicatorLeft || right != mIndicatorRight) {
                mIndicatorLeft = left;
                mIndicatorRight = right;
                ViewCompat.postInvalidateOnAnimation(this);
            }
        }

        void animateIndicatorToPosition(final int position, int duration) {
            if (mIndicatorAnimator != null && mIndicatorAnimator.isRunning()) {
                mIndicatorAnimator.cancel();
            }
            final boolean isRtl = ViewCompat.getLayoutDirection(this)
                    == ViewCompat.LAYOUT_DIRECTION_RTL;
            final View targetView = getChildAt(position);
            if (targetView == null) {
                updateIndicatorPosition();
                return;
            }
            final int targetLeft = targetView.getLeft();
            final int targetRight = targetView.getRight();
            final int startLeft;
            final int startRight;
            if (Math.abs(position - mSelectedPosition) <= 1) {
                startLeft = mIndicatorLeft;
                startRight = mIndicatorRight;
            } else {
                final int offset = dpToPx(MOTION_NON_ADJACENT_OFFSET);
                if (position < mSelectedPosition) {
                    if (isRtl) {
                        startLeft = startRight = targetLeft - offset;
                    } else {
                        startLeft = startRight = targetRight + offset;
                    }
                } else {
                    if (isRtl) {
                        startLeft = startRight = targetRight + offset;
                    } else {
                        startLeft = startRight = targetLeft - offset;
                    }
                }
            }
            if (startLeft != targetLeft || startRight != targetRight) {
                ValueAnimatorCompat animator = mIndicatorAnimator = ViewUtils.createAnimator();
                animator.setInterpolator(AnimationUtils.FAST_OUT_SLOW_IN_INTERPOLATOR);
                animator.setDuration(duration);
                animator.setFloatValues(0, 1);
                animator.setUpdateListener(new ValueAnimatorCompat.AnimatorUpdateListener() {
                    @Override
                    public void onAnimationUpdate(ValueAnimatorCompat animator) {
                        final float fraction = animator.getAnimatedFraction();
                        setIndicatorPosition(
                                AnimationUtils.lerp(startLeft, targetLeft, fraction),
                                AnimationUtils.lerp(startRight, targetRight, fraction));
                    }
                });
                animator.setListener(new ValueAnimatorCompat.AnimatorListenerAdapter() {
                    @Override
                    public void onAnimationEnd(ValueAnimatorCompat animator) {
                        mSelectedPosition = position;
                        mSelectionOffset = 0f;
                    }
                });
                animator.start();
            }
        }

        @Override
        public void draw(Canvas canvas) {
            super.draw(canvas);
            if (mIndicatorLeft >= 0 && mIndicatorRight > mIndicatorLeft) {
                if (mSelectedIndicatorWidth != 0 && !xTabDividerWidthWidthText) {
                    int maxWidth = mIndicatorRight - mIndicatorLeft;
                    if (maxWidth > mSelectedIndicatorWidth) {
                        mIndicatorLeft += (maxWidth - mSelectedIndicatorWidth) / 2;
                        mIndicatorRight -= (maxWidth - mSelectedIndicatorWidth) / 2;
                    }
                } else {
                    int maxWidth = mIndicatorRight - mIndicatorLeft;
                    if (maxWidth > mSelectedTab.getTextWidth()) {
                        mIndicatorLeft += (maxWidth - mSelectedTab.getTextWidth()) / 2;
                        mIndicatorRight -= (maxWidth - mSelectedTab.getTextWidth()) / 2;
                    }
                }
                canvas.drawRect(mIndicatorLeft, getHeight() - mSelectedIndicatorHeight,
                        mIndicatorRight, getHeight(), mSelectedIndicatorPaint);
            }
        }
    }

    public class TabItem extends View {
        final CharSequence mText;
        final Drawable mIcon;
        final int mCustomLayout;

        public TabItem(Context context) {
            this(context, null);
        }

        @SuppressLint("RestrictedApi")
        public TabItem(Context context, AttributeSet attrs) {
            super(context, attrs);
            final TintTypedArray a = TintTypedArray.obtainStyledAttributes(context, attrs,
                    R.styleable.TabItem);
            mText = a.getText(R.styleable.TabItem_android_text);
            mIcon = a.getDrawable(R.styleable.TabItem_android_icon);
            mCustomLayout = a.getResourceId(R.styleable.TabItem_android_layout, 0);
            a.recycle();
        }
    }

    class DividerDrawable extends Drawable {
        final static int TOP = 0;
        final static int CENTER = 1;
        final static int BOTTOM = 2;
        private final Paint paint;
        private final int color = Color.BLACK;
        private RectF rectF;
        private int height = 0;
        private int width;
        private int gravity = CENTER;

        DividerDrawable(Context context) {
            width = dip2px(context, 2);
            paint = new Paint();
            paint.setColor(color);
            paint.setAntiAlias(true);
        }

        void setColor(int color) {
            paint.setColor(color);
        }

        void setGravity(int gravity) {
            if (gravity != TOP && gravity != CENTER && gravity != BOTTOM) {
                throw new IllegalArgumentException("Gravity must be one of 0(DividerDrawable.TOP)、" +
                        "1(DividerDrawable.CENTER) and 2(DividerDrawable.BOTTOM)");
            }
            this.gravity = gravity;
        }

        @Override
        public void draw(@NonNull Canvas canvas) {
            canvas.drawColor(Color.TRANSPARENT);
            if (height == 0 || height >= rectF.bottom) {
                canvas.drawRect(rectF, paint);
            } else {
                int margin = (int) ((rectF.bottom - height) / 2);
                switch (gravity) {
                    case TOP:
                        canvas.drawRect(rectF.left, rectF.top, rectF.right, rectF.bottom - margin * 2, paint);
                        break;
                    case CENTER:
                        canvas.drawRect(rectF.left, rectF.top + margin, rectF.right, rectF.bottom - margin, paint);
                        break;
                    case BOTTOM:
                        canvas.drawRect(rectF.left, rectF.top + margin * 2, rectF.right, rectF.bottom, paint);
                        break;
                }
            }
        }

        @Override
        public void setBounds(int left, int top, int right, int bottom) {
            super.setBounds(left, top, right, bottom);
            rectF = new RectF(left, top, right, bottom);
        }

        void setDividerSize(int width, int height) {
            this.width = width;
            this.height = height;
            invalidateSelf();
        }

        @Override
        public int getIntrinsicHeight() {
            return super.getIntrinsicHeight();
        }

        @Override
        public int getIntrinsicWidth() {
            return width;
        }

        @Override
        public void setAlpha(int alpha) {
            paint.setAlpha(alpha);
        }

        @Override
        public void setColorFilter(ColorFilter colorFilter) {
            paint.setColorFilter(colorFilter);
        }

        @Override
        public int getOpacity() {
            return PixelFormat.TRANSLUCENT;
        }

        int dip2px(Context context, float dpValue) {
            final float scale = context.getResources().getDisplayMetrics().density;
            return (int) (dpValue * scale + 0.5f);
        }
    }

    private class PagerAdapterObserver extends DataSetObserver {
        @Override
        public void onChanged() {
            populateFromPagerAdapter();
        }

        @Override
        public void onInvalidated() {
            populateFromPagerAdapter();
        }
    }
}
